package com.aabte.commons.util;

import org.apache.commons.lang3.StringUtils;

import javax.naming.InsufficientResourcesException;
import java.io.FileNotFoundException;
import java.net.BindException;
import java.security.AccessControlException;
import java.security.acl.NotOwnerException;
import java.sql.SQLException;
import java.util.ConcurrentModificationException;
import java.util.List;
import java.util.MissingResourceException;
import java.util.jar.JarException;

/**
 * @author Daniel
 */
public class ExceptionUtils {

    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    public static final String MESSAGE = "***";

    /**
     * 将 Exception 转化为 String
     */
    public static String getErrorStack(Throwable throwable) {
        Throwable t = throwable;
        if (t == null) {
            return "";
        }

        StringBuilder buffer = new StringBuilder();
        buffer.append(LINE_SEPARATOR);

        int i = 0;

        do {
            if (i > 0) {
                buffer.append("Caused by: ");
            }

            String message;
            if (isSpecialException(t)) {
                message = "***";
            } else {
                message = t.getMessage();
            }

            buffer.append(t.getClass().getName()).append(": ").append(message).append(LINE_SEPARATOR);

            StackTraceElement[] stackTraceElements = t.getStackTrace();
            for (StackTraceElement stackTraceElement : stackTraceElements) {
                retrieveStackTrace(stackTraceElement, buffer);
            }
            t = t.getCause();
            ++i;
        } while (t != null);

        return buffer.toString();
    }

    /**
     * 获取根因的Message
     */
    public static String getCauseMessage(Throwable throwable) {
        String errorMessage = null;
        List<Throwable> throwableList = getThrowableList(throwable);
        for (int i = throwableList.size() - 1; i >= 0; i--) {
            Throwable last = throwableList.get(0);
            errorMessage = getErrorMessage(last);
            if (StringUtils.isBlank(errorMessage) || StringUtils.equals(errorMessage, MESSAGE)) {
                continue;
            }
            break;
        }
        return null == errorMessage ? "" : errorMessage;
    }

    public static List<Throwable> getThrowableList(Throwable throwable) {
        return org.apache.commons.lang3.exception.ExceptionUtils
                .getThrowableList(throwable);
    }

    public static String getErrorMessage(Throwable t) {
        String message;
        if (isSpecialException(t)) {
            message = MESSAGE;
        } else {
            message = t.getMessage();
        }
        return message;
    }

    private static void retrieveStackTrace(
            StackTraceElement stackTraceElement, StringBuilder buffer) {
        if (null == stackTraceElement || null == buffer) {
            return;
        }
        buffer.append("\t").append(stackTraceElement.toString()).append(LINE_SEPARATOR);
    }

    private static boolean isSpecialException(Throwable t) {
        return isSpecialExceptionPart1(t) || isSpecialExceptionPart2(t);
    }

    private static boolean isSpecialExceptionPart1(Throwable t) {
        return t instanceof FileNotFoundException
                || t instanceof SQLException
                || t instanceof BindException
                || t instanceof ConcurrentModificationException
                || t instanceof InsufficientResourcesException
                || t instanceof MissingResourceException;
    }

    private static boolean isSpecialExceptionPart2(Throwable t) {
        return t instanceof JarException
                || t instanceof OutOfMemoryError
                || t instanceof StackOverflowError
                || t instanceof NotOwnerException
                || t instanceof AccessControlException;
    }
}
